﻿using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Xml.Linq;
using Microsoft.CSharp;

namespace MetadataProcessor
{
    public class MetadataController
    {
        private static CompilerResults _loCompiled = null;
        private static Assembly _assembly = null;
        public static object GetInstance(string name)
        {
            return _assembly.CreateInstance(name);
        }

        public static Type GetType(string name)
        {
            return _assembly.GetType(name);
        }

        public static void GenerateAssembly()
        {
            string lcCode = GetNamespaces();
            var doc = XDocument.Load("ReportMetadata.xml");
            var rootElement = doc.Element("Entities");
            foreach (var element in rootElement.Elements())
            {
                GenereteClass(element, ref lcCode);
            }
            lcCode += Environment.NewLine;
            lcCode += "}";
            _assembly = GenerateAssembly(lcCode);
            
        }

        private static Assembly GenerateAssembly(string lcCode)
        {
            ICodeCompiler loCompiler = new CSharpCodeProvider().CreateCompiler();
            CompilerParameters loParameters = new CompilerParameters();
            loParameters.ReferencedAssemblies.Add("System.dll");
            loParameters.ReferencedAssemblies.Add("System.Core.dll");
            loParameters.ReferencedAssemblies.Add("DevExpress.Xpo.v11.1.dll");
            loParameters.ReferencedAssemblies.Add("DevExpress.Data.v11.1.dll");


            loParameters.GenerateInMemory = false;

            _loCompiled = loCompiler.CompileAssemblyFromSource(loParameters, lcCode);
            if (_loCompiled.Errors.HasErrors)
            {

                string lcErrorMsg = "";



                lcErrorMsg = _loCompiled.Errors.Count.ToString() + ") Errors:";

                for (int x = 0; x < _loCompiled.Errors.Count; x++)

                    lcErrorMsg = lcErrorMsg + "\r\nLine: " +

                                 _loCompiled.Errors[x].Line.ToString() + " - " +

                                 _loCompiled.Errors[x].ErrorText;



                Debugger.Break();
            }
            return _loCompiled.CompiledAssembly;

        }

        private static void GenereteClass(XElement element, ref string lcCode)
        {
            lcCode += Environment.NewLine + @"public class " + element.Name +
                      @": XPObject 
                                                {
                                                    public " +
                      element.Name +
                      @"(): base()
                                                    {}
                                                    public " +
                      element.Name + @"(Session session): base(session){}";
            foreach (var property in element.Elements())
            {
                lcCode += Environment.NewLine;
                string prop = @"[DisplayName(" + "\"" + property.Name + "\"" + @")]
                            private " + GetAttributeValue(property, "DataType") + " _" + property.Name
                            + "; public " + GetAttributeValue(property, "DataType") + " " + property.Name
                            + @"{
                                get
                                {
                                    return _" + property.Name + @";
                                }
                                set
                                {
                                    SetPropertyValue(" + "\"" + property.Name + "\"" + @", ref _" + property.Name + @", value);
                                }
                            }  ";

                //lcCode += string.Format("public {0} {1} {2} set;get;{3}", GetAttributeValue(property, "DataType"),
                //                        property.Name, "{", "}");
                lcCode += prop;
            }
            lcCode += Environment.NewLine;
            lcCode += "}";
        }

        private static string GetAttributeValue(XElement element, string name)
        {
            var att = element.Attribute(name);
            return att != null ? att.Value : string.Empty;
        }

        private static string GetNamespaces()
        {
            return @"using System;
                    using System.Linq;
                    using System.Collections.Generic;
                    using System.IO;
                    using DevExpress.Xpo;
                    namespace ReportDTO
                    {";
        }

        public static List<string> GetEntities()
        {
            var entities = new List<string>();
            var types = _assembly.GetTypes();
            foreach (var type in types)
            {
                entities.Add(type.Name);
            }
            return entities;
        }
    }
}
